import { DndItemTypes, EditorGlobalContext } from "components/editor/main/consts";
import { Fragment, useContext, useEffect, useRef, useState } from "react";
import { useDrop } from "react-dnd";
import Moveable from "react-moveable";
import { v4 as uuidV4 } from "uuid";

import { ArrayOpt, EditorPageInfoOpt, PropsOpt } from "./../../../utils/tools";
import { cloneDeep, isPlainObject } from "lodash";
import { useHotkeys } from "react-hotkeys-hook";

export default function CanvasContainer({ moveableRef, moveableTargets, groupManagerRef, selectoRef, setSelectedTargets }) {
	// 全局数据
	const { gEditorConfig, editorPageInfo, setEditorPageInfo, selectedItems, setSelectedItems } = useContext(EditorGlobalContext);
	// console.log(gEditorConfig, editorPageInfo);

	const addItemToEditorData = ({ uuid, type, props }) => {
		const editorPageInfoClone = cloneDeep(editorPageInfo);
		editorPageInfoClone.body.push({
			uuid,
			type,
			props,
			body: []
		});

		setEditorPageInfo(editorPageInfoClone);
	};

	const moveFunc = {
		isResizable: (item, selectedItems) => {
			if (selectedItems.length === 1) {
				const index = ArrayOpt.indexOf({
					data: selectedItems,
					value: item.uuid,
					isJson: true,
					key: "uuid"
				});
				return index !== -1;
			}
		},
		updateItemSize: event => {
			// console.log(event.lastEvent);
			if (!event.lastEvent) return;
			const size = { w: 0, h: 0 };
			const widthStr = event.lastEvent.width;
			const heightStr = event.lastEvent.height;
			size.w = widthStr;
			size.h = heightStr;

			let pos = {};
			const posCss = event.lastEvent.afterTransform;
			if (posCss.indexOf("translate") !== -1) {
				pos = comFunc.getItemPosByCssText(posCss);
			}

			const uuid = event.target.getAttribute("data-uuid");

			Object.assign(pos, size);
			console.log(pos);
			moveFunc.changeItemData(uuid, pos);
		},
		updateGroupItemSize: event => {
			const events = event.events;
			events.map(item => {
				moveFunc.updateItemSize(item);
			});
		},

		updateItemPos: event => {
			if (!event?.cssText || event?.cssText.indexOf("transform") === -1) {
				console.log("pos data is error!");
				return;
			}

			const pos = comFunc.getItemPosByCssText(event.cssText);
			const uuid = event.target.getAttribute("data-uuid");

			if (JSON.stringify(pos) === "{}") {
				console.log("pos data is update error");
				return;
			}

			moveFunc.changeItemData(uuid, pos);
		},

		updateGroupItemPos: event => {
			const targets = event.targets;
			targets.map(item => {
				const uuid = item.getAttribute("data-uuid");
				const cssText = item.getAttribute("style");
				const pos = comFunc.getItemPosByCssText(cssText);

				if (JSON.stringify(pos) === "{}") {
					console.log("pos data is update error");
					return;
				}

				moveFunc.changeItemData(uuid, pos);
			});
		},

		onRender: event => {
			event.target.style.cssText += event.cssText;
		},
		onDrag: event => {
			event.target.style.cssText += event.cssText;
		},
		onDragEnd: event => {
			if (!event.lastEvent) return;
			const rect = event.lastEvent.beforeTranslate;
			const curPos = {
				x: rect[0],
				y: rect[1]
			};

			const uuid = event.target.getAttribute("data-uuid");
			moveFunc.changeItemData(uuid, curPos);
		},
		changeItemData: (uuid, pos) => {
			const editorPageInfoData = EditorPageInfoOpt.updateEditorPageItem(editorPageInfo, {
				uuid,
				props: pos
			});

			setEditorPageInfo(editorPageInfoData);
			// LocalStorageOpt.set(ItemTypes.EDITOR_DATA_IS_SAVED, false);
		}
	};

	const comFunc = {
		eventStop: event => {
			event.stopPropagation();
		},
		selectedItems: {
			set: (uuid, type) => {
				setSelectedItems([
					{
						uuid,
						type
					}
				]);
			},
			setArray: arr => {
				setSelectedItems(arr);
			},
			clear: () => {
				setSelectedItems([]);
			}
		},
		getItemPosByCssText: data => {
			const pos = {};

			const regexParent = /translate\(([\d.-]+)px,\s*([\d.-]+)px\)/;
			const matchesParent = data.match(regexParent);
			if (matchesParent && matchesParent[0].indexOf("translate") === -1) return pos;

			const regex = /-?\d+\.?\d*/g;
			const matches = matchesParent[0].match(regex);
			if (matches.length !== 2) {
				// console.log("pos data get is error");
				return pos;
			}

			pos.x = parseInt(matches[0], 10);
			pos.y = parseInt(matches[1], 10);

			return pos;
		},
		reloadElements: () => {
			setTimeout(() => {
				// const elements = selectoRef.current.getSelectableElements();
				// groupManagerRef.current = new GroupManager([], elements);
			}, 100);
		}
	};

	const moveItemFunc = {
		onClick: (event, item) => {
			comFunc.selectedItems.set(item.uuid, item.type);
			comFunc.eventStop(event);
		}
	};

	const renderComponent = ({ type, props }) => {
		const { config } = global.GEditorData;

		if (!config[type]) return `<div> ${type} component is render error !</div>`;

		// console.log(config);
		return config[type].component(props);
	};

	const getStyleByProp = propItem => {
		// console.log(propItem);
		const style = {
			position: "relative",
			width: `${propItem?.w ?? 800}px`,
			height: `${propItem?.h ?? 600}px`,
			backgroundColor: `${propItem?.backgroundColor ?? "#ebeced"}`,
			opacity: `${propItem?.opacity / 100 ?? 1}`,
			zIndex: `${propItem?.zIndex ?? 0}`
		};
		return style;
	};

	const renderPage = {
		renderMoveItem: item => {
			return (
				<Fragment key={item.uuid}>
					<div
						className={`target target-${item.uuid}`}
						data-uuid={item.uuid}
						data-type={item.type}
						style={{
							width: item.props.w ?? 100 + "px",
							height: item.props.h ?? 50 + "px",
							transform: `translate(${item.props.x ?? 0}px, ${item.props.y ?? 0}px)`,
							position: "absolute"
						}}
						onClick={event => moveItemFunc.onClick(event, item)}>
						{renderComponent({
							type: item.type,
							props: item
						})}
					</div>
				</Fragment>
			);
		},
		renderMoveAble: () => {
			return (
				<Moveable
					ref={moveableRef}
					target={moveableTargets}
					scalable={true}
					resizable={true}
					draggable={true}
					snappable={true}
					keepRatio={false}
					bounds={{ left: 0, top: 0, right: editorPageInfo?.props?.w ?? 1920, bottom: editorPageInfo?.props?.h ?? 1080 }}
					onResizeEnd={event => moveFunc.updateItemSize(event)}
					onDragEnd={event => moveFunc.onDragEnd(event)}
					onRender={event => {
						moveFunc.onRender(event);
					}}
					onDrag={e => {
						e.target.style.cssText += e.cssText;
					}}
					onClickGroup={e => {
						// console.log(8);
						if (!e.moveableTarget) {
							setSelectedTargets([]);
							return;
						}

						if (e.isDouble) {
							const childs = groupManagerRef.current.selectSubChilds(moveableTargets, e.moveableTarget);
							setSelectedTargets(childs.targets());
							return;
						}

						if (e.isTrusted) {
							selectoRef.current.clickTarget(e.inputEvent, e.moveableTarget);
						}
					}}
					onRenderGroup={e => {
						e.events.forEach(ev => {
							ev.target.style.cssText += ev.cssText;
						});
					}}
					onDragGroupEnd={ev => moveFunc.updateGroupItemPos(ev)}
					onResizeGroupEnd={ev => moveFunc.updateGroupItemSize(ev)}
					// onDragStart={event => moveFunc.onDragStart(event)}
					// onBeforeRenderStart={event => moveFunc.onDragStart(event)}
				/>
			);
		}
	};

	const dropFunc = {
		getItem: (type, localPos) => {
			const uuid = uuidV4();
			// console.log(gEditorConfig);
			const config = gEditorConfig.config[type];
			const propsData = {};
			if (config) {
				const defaultProps = config.property?.default;
				const customProps = config.property?.custom;
				const propsObj = PropsOpt.get(defaultProps, customProps);

				Object.values(propsObj).map(item => {
					propsData[item.name] = item.default;
				});
				Object.assign(propsData, localPos);
			}

			return {
				uuid,
				type,
				props: propsData
			};
		},
		addItem: (item, monitor, localPos) => {
			const itemInfo = dropFunc.getItem(item.type, localPos);
			addItemToEditorData(itemInfo);
		},
		getCloneItem: (type, data) => {
			const uuid = uuidV4();
			const propsData = cloneDeep(data);
			propsData.x += 20;
			propsData.y += 20;
			return {
				uuid,
				type,
				props: data
			};
		}
	};

	const dropRef = useRef(null);
	const [, dropContainer] = useDrop(
		() => ({
			accept: DndItemTypes.COMPONENT_ITEM,
			drop(item, monitor) {
				const dropBasePos = dropRef.current?.getBoundingClientRect();
				if (!dropBasePos) return;

				const globalPos = monitor.getClientOffset();

				const localPos = {
					x: globalPos.x - dropBasePos.x,
					y: globalPos.y - dropBasePos.y
				};

				dropFunc.addItem(item, monitor, localPos);

				comFunc.reloadElements();

				// global.gEditorConfig.isEditable = false;

				// 拖动一个元素后设置其标志位为：可编辑
				// LocalStorageOpt.set(ItemTypes.EDITOR_DATA_IS_SAVED, false);
			}
		}),
		[gEditorConfig, editorPageInfo]
	);

	dropContainer(dropRef);

	// canvas画布相关方法
	const canvasContainerClickHandle = () => {
		// console.log(editorPageInfo);
		comFunc.selectedItems.set(editorPageInfo.uuid, editorPageInfo.type);
		// comFunc.selectedItems.clear();
	};

	const [copyInfo, setCopyInfo] = useState({});
	const hotKeyFunc = {
		copy: () => {
			const uuidArr = [];
			selectedItems.map(item => {
				uuidArr.push(item.uuid);
			});

			if (selectedItems.length === 1) {
				const uuid = selectedItems[0].uuid;
				const rootUuid = editorPageInfo.uuid;
				// console.log(uuid, rootUuid);
				if (uuid !== rootUuid) {
					const type = selectedItems[0].type;
					const editorPageInfoMap = EditorPageInfoOpt.toMap(editorPageInfo);
					const itemInfoValue = editorPageInfoMap[uuid];
					const itemInfo = dropFunc.getCloneItem(type, itemInfoValue.props);
					setCopyInfo(itemInfo);

					console.log(itemInfo);
				} else {
					// 根节点
					// LayerMsg("不能复制根节点!");
				}
			}
		},
		paste: () => {
			if (isPlainObject(copyInfo) && JSON.stringify(copyInfo) !== "{}") {
				addItemToEditorData(copyInfo);
				setCopyInfo(copyInfo);

				// 粘贴后设置粘贴项选中
				comFunc.selectedItems.set(copyInfo.uuid, copyInfo.type);
				comFunc.reloadElements();
			} else {
				// LayerMsg("请选择复制项!");
			}
		},
		delete: () => {
			const uuidArr = [];
			selectedItems &&
				selectedItems.map(item => {
					// const uuid = item.getAttribute("data-uuid");
					// if (uuid) uuidArr.push(uuid);
					uuidArr.push(item.uuid);
				});

			const setEditorPageInfoClone = EditorPageInfoOpt.deleteEditorPageItem(editorPageInfo, uuidArr);
			setEditorPageInfo(setEditorPageInfoClone);

			comFunc.selectedItems.clear();
			comFunc.reloadElements();
		}
	};

	// 添加快捷键
	useHotkeys(
		"delete",
		() => {
			hotKeyFunc.delete();
		},
		{},
		[selectedItems, moveableTargets]
	);
	useHotkeys(
		"ctrl+c",
		() => {
			hotKeyFunc.copy();
		},
		{},
		[selectedItems, moveableTargets]
	);
	useHotkeys(
		"ctrl+v",
		() => {
			hotKeyFunc.paste();
		},
		{},
		[copyInfo, moveableTargets]
	);

	return (
		<div className="canvas-container" style={getStyleByProp()} ref={dropRef} onClick={canvasContainerClickHandle}>
			{renderPage.renderMoveAble()}
			<div className="elements selecto-area">
				{editorPageInfo &&
					editorPageInfo.body &&
					editorPageInfo.body.map(citem => {
						return renderPage.renderMoveItem(citem);
					})}
			</div>
		</div>
	);
}
